`include "defines.v"

module cpu(

    input                               clock,
    input                               reset,

    output                              axi_valid,
    input                               axi_ready,
    output                              axi_req,
    input  [63:0]                       axi_data_read,
    output [63:0]                       axi_data_write,
    output [63:0]                       axi_addr,
    output [1:0]                        axi_size,
    input  [1:0]                        axi_resp
          
);
//if
wire                       	if_valid_o;
wire [`AXI_ADDR_WIDTH-1:0] 	if_addr_o;
wire [1:0]                 	if_size_o;
//if_reg
wire [`RAM_BUS] 	if_pc_i;
wire [31:0]     	if_inst_i;
wire            	if_reg_valid_i;

wire [`RAM_BUS] 	if_pc_o;
wire [31:0]     	if_inst_o;
wire            	if_reg_valid_o;
//id
wire              	id_rs1_r_ena_o;
wire [`REG_BUS]   	id_rs1_r_addr_o;
wire              	id_rs2_r_ena_o;
wire [`REG_BUS]   	id_rs2_r_addr_o;

wire              	jump_o;
wire [`RAM_BUS]   	new_pc_o;
wire                id_branch_tag_o;
//id_reg
wire [`RAM_BUS]   	id_pc_i;
wire [`REG_WIDTH] 	id_op1_i;
wire [`REG_WIDTH] 	id_op2_i;
wire [`REG_WIDTH] 	id_imm_i;
wire [5:0]        	id_aluop_i;
wire              	id_skip_i;
wire                id_ecall_i;
wire                id_mret_i;
wire              	id_rd_w_ena_i;
wire [`REG_BUS]   	id_rd_w_addr_i;
wire              	id_csr_r_ena_i;
wire              	id_csr_w_ena_i;
wire [11:0]       	id_csr_addr_i;

wire [`RAM_BUS]   	id_pc_o;
wire [31:0]         id_inst_o;
wire [`REG_WIDTH] 	id_op1_o;
wire [`REG_WIDTH] 	id_op2_o;
wire [`REG_WIDTH] 	id_imm_o;
wire [5:0]        	id_aluop_o;
wire              	id_skip_o;
wire				id_ecall_o;
wire                id_mret_o;
wire              	id_rd_w_ena_o;
wire [`REG_BUS]   	id_rd_w_addr_o;
wire              	id_csr_r_ena_o;
wire              	id_csr_w_ena_o;
wire [11:0]       	id_csr_addr_o;
wire              	id_reg_valid_o;
//exe
wire [`REG_WIDTH] 	csr_data_o;
wire                exe_data_valid_o;

//exe_reg
wire              	exe_rd_w_ena_i;
wire [`REG_BUS]   	exe_rd_w_addr_i;
wire [`REG_WIDTH] 	exe_rd_w_data_i;
wire [5:0]        	exe_aluop_i;
wire [`RAM_BUS]   	exe_mem_addr_i;
wire [`REG_WIDTH] 	exe_rs2_i;
wire              	exe_halt_ena_i;
wire              	exe_skip_i;

wire [`RAM_BUS]     exe_pc_o;
wire [31:0]         exe_inst_o;
wire              	exe_rd_w_ena_o;
wire [`REG_BUS]   	exe_rd_w_addr_o;
wire [`REG_WIDTH] 	exe_rd_w_data_o;
wire [5:0]        	exe_aluop_o;
wire [`RAM_BUS]   	exe_mem_addr_o;
wire [`REG_WIDTH] 	exe_rs2_o;
wire              	exe_halt_ena_o;
wire              	exe_skip_o;
wire              	exe_reg_valid_o;
//mem
wire  				clint_wr_o;
wire  				clint_rd_o;
wire    			mtime_ena_o;
wire                mtimecmp_ena_o;
wire              	mem_read_req_o;
wire              	mem_write_req_o;
wire              	mem_valid_o;
wire [`RAM_BUS]   	mem_addr_o;
wire [1:0]        	mem_size_o;
wire [`RAM_WIDTH] 	mem_data_write_o;
wire                mem_data_valid_o;

//mem_reg
wire              	mem_rd_w_ena_i;
wire [`REG_BUS]   	mem_rd_w_addr_i;
wire [`REG_WIDTH] 	mem_rd_w_data_i;
wire              	mem_halt_ena_i;
wire              	mem_skip_i;
wire              	mem_reg_valid_i;

wire [`RAM_BUS]     mem_pc_o;
wire [31:0]         mem_inst_o;
wire              	mem_rd_w_ena_o;
wire [`REG_BUS]   	mem_rd_w_addr_o;
wire [`REG_WIDTH] 	mem_rd_w_data_o;
wire              	mem_halt_ena_o;
wire              	mem_skip_o;
wire              	mem_reg_valid_o;

wire [`REG_WIDTH] 	mem_mstatus_o;
wire [`REG_WIDTH] 	mem_mie_o;
wire [`REG_WIDTH] 	mem_mtvec_o;
wire [`REG_WIDTH] 	mem_mepc_o;
wire [`REG_WIDTH] 	mem_mcause_o;
wire [`REG_WIDTH] 	mem_mtval_o;
wire [`REG_WIDTH] 	mem_mip_o;
wire [`REG_WIDTH] 	mem_medeleg_o;
wire [`REG_WIDTH] 	mem_mideleg_o;
wire [`REG_WIDTH] 	mem_mscratch_o;

//wb

//wb_reg
wire [`RAM_BUS]   	wb_pc_i;
wire              	wb_rd_w_ena_i;
wire [`REG_BUS]   	wb_rd_w_addr_i;
wire [`REG_WIDTH] 	wb_rd_w_data_i;
wire              	wb_halt_ena_i;
wire              	wb_skip_i;

wire [`RAM_BUS]   	wb_pc_o;
wire [31:0]         wb_inst_o;
wire              	wb_rd_w_ena_o;
wire [`REG_BUS]   	wb_rd_w_addr_o;
wire [`REG_WIDTH] 	wb_rd_w_data_o;
wire              	wb_halt_ena_o;
wire              	wb_skip_o;
wire              	wb_reg_valid_o;

wire [`REG_WIDTH] 	wb_mstatus_o;
wire [`REG_WIDTH] 	wb_mie_o;
wire [`REG_WIDTH] 	wb_mtvec_o;
wire [`REG_WIDTH] 	wb_mepc_o;
wire [`REG_WIDTH] 	wb_mcause_o;
wire [`REG_WIDTH] 	wb_mtval_o;
wire [`REG_WIDTH] 	wb_mip_o;
wire [`REG_WIDTH] 	wb_medeleg_o;
wire [`REG_WIDTH] 	wb_mideleg_o;
wire [`REG_WIDTH] 	wb_mscratch_o;
//regfile
wire [`REG_WIDTH] 	rs1_data_o;
wire [`REG_WIDTH] 	rs2_data_o;
wire [`REG_WIDTH] 	regs_o[0:31];
//csr_regfile
wire            clint_o;
wire [63:0] 	csr_rd_data;
wire [63:0] 	mstatus_o;
wire [63:0] 	mie_o;
wire [63:0]		mtvec_o;
wire [63:0] 	mepc_o;
wire [63:0] 	mcause_o;
wire [63:0] 	mtval_o;
wire [63:0] 	mip_o;
wire [63:0] 	mcycle_o;
wire [63:0] 	minstret_o;
wire [63:0] 	medeleg_o;
wire [63:0] 	mideleg_o;
wire [63:0] 	mscratch_o;
wire [63:0] 	sstatus_o;
//clint
wire [`REG_WIDTH] 	mtime_o;
wire [`REG_WIDTH] 	mtimecmp_o;
wire                clint_interrupt_o;
//scu
wire [4:0] 	stall_ena_o;
wire [4:0] 	pipe_rst_o;
wire        mem_req_o;
wire wb_stall_i, mem_stall_i, exe_stall_i, id_stall_i, if_stall_i;
wire wb_rst_i, mem_rst_i,  exe_rst_i,   id_rst_i,   if_rst_i;
assign {wb_stall_i,mem_stall_i,exe_stall_i, id_stall_i, if_stall_i} = stall_ena_o;
assign {wb_rst_i,  mem_rst_i,  exe_rst_i,   id_rst_i,   if_rst_i}   = pipe_rst_o;
//data_ctr
wire [`REG_WIDTH] 	id_rs1_data_o;
wire [`REG_WIDTH] 	id_rs2_data_o;
wire                id_hit_o;
//arbiter
wire        	if_ready_o;
wire [63:0] 	if_data_read_o;
wire        	mem_ready_o;
wire [63:0] 	mem_data_read_o;
wire            arbiter_state_o;

 pc u_pc(
    .clk            		( clock          		),
    .rst            		( reset              	),
    .if_ready_i     		( if_ready_o     		),
    .if_data_read_i 		( if_data_read_o 		),
    .if_valid_o     		( if_valid_o     		),
    .if_addr_o      		( if_addr_o      		),
    .if_size_o      		( if_size_o      		),
    .jump_ena_i     		( jump_o     		    ),
	.mem_req_i				( mem_req_o				),
    .new_pc_i       		( new_pc_o       		),
	.clint_i				( clint_o				),
	.ecall_i				( id_ecall_i			),
	.mret_i               	( id_mret_i				),
	.mtvec_i				( mtvec_o				),
	.mepc_i				    ( mepc_o				),
    .pc_o           		( if_pc_i               ),
    .inst_o         		( if_inst_i             ),
    .if_reg_valid_o 		( if_reg_valid_i 		)
);


if_reg u_if_reg(
	.clk            		( clock            		),
	.rst            		( reset | if_rst_i      ),
	.if_stall_i     		( if_stall_i     		),
	.if_pc_i        		( if_pc_i        		),
	.if_inst_i      		( if_inst_i      		),
	.if_reg_valid_i 		( if_reg_valid_i 		),
	.if_pc_o        		( if_pc_o        		),
	.if_inst_o      		( if_inst_o      		),
	.if_reg_valid_o 		( if_reg_valid_o 		)
);


id u_id(
	//ports
	.rst          			( reset          		),
	.instr_i      			( if_inst_o      		),
	.pc_i         			( if_pc_o         	),
	.rs1_data_i   			( id_rs1_data_o  		),
	.rs2_data_i   			( id_rs2_data_o  		),
	.rs1_r_ena_o  			( id_rs1_r_ena_o  		),
	.rs1_r_addr_o 			( id_rs1_r_addr_o 		),
	.rs2_r_ena_o  			( id_rs2_r_ena_o  		),
	.rs2_r_addr_o 			( id_rs2_r_addr_o 		),
	.rd_w_ena_o   			( id_rd_w_ena_i   		),
	.rd_w_addr_o  			( id_rd_w_addr_i  		),
	.csr_r_ena_o  			( id_csr_r_ena_i  		),
	.csr_w_ena_o  			( id_csr_w_ena_i  		),
	.csr_addr_o   			( id_csr_addr_i   		),
	.op1_o        			( id_op1_i        		),
	.op2_o        			( id_op2_i        		),
	.imm_o        			( id_imm_i        		),
	.aluop_o      			( id_aluop_i      		),
	.pc_o         			( id_pc_i         		),
	.jump_o       			( jump_o       		    ),
	.new_pc_o     			( new_pc_o     		    ),
	.skip_id_o    			( id_skip_i    		    ),
	.id_branch_tag_o		( id_branch_tag_o       ),
	.ecall_o				( id_ecall_i			),
	.mret_o					( id_mret_i				)
);


id_reg u_id_reg(
	//ports
	.clk            		( clock            		),
	.rst            		( reset|id_rst_i|clint_o),
	.id_stall_i     		( id_stall_i     		),
	.id_pc_i        		( id_pc_i        		),
	.id_inst_i              ( if_inst_o             ),
	.id_op1_i       		( id_op1_i       		),
	.id_op2_i       		( id_op2_i       		),
	.id_imm_i       		( id_imm_i       		),
	.id_aluop_i     		( id_aluop_i     		),
	.id_skip_i      		( id_skip_i      		),
	.id_ecall_i				( id_ecall_i			),
	.id_mret_i				( id_mret_i				),
	.id_rd_w_ena_i  		( id_rd_w_ena_i  		),
	.id_rd_w_addr_i 		( id_rd_w_addr_i 		),
	.id_csr_r_ena_i			( id_csr_r_ena_i		),
	.id_csr_w_ena_i 		( id_csr_w_ena_i 		),
	.id_csr_addr_i  		( id_csr_addr_i  		),
	.id_reg_valid_i 		( if_reg_valid_o 		),
	.id_pc_o        		( id_pc_o        		),
	.id_inst_o              ( id_inst_o             ),
	.id_op1_o       		( id_op1_o       		),
	.id_op2_o       		( id_op2_o       		),
	.id_imm_o       		( id_imm_o       		),
	.id_aluop_o     		( id_aluop_o     		),
	.id_skip_o      		( id_skip_o      		),
	.id_ecall_o				( id_ecall_o			),
	.id_mret_o              ( id_mret_o				),
	.id_rd_w_ena_o  		( id_rd_w_ena_o  		),
	.id_rd_w_addr_o 		( id_rd_w_addr_o 		),
	.id_csr_r_ena_o		    ( id_csr_r_ena_o		),
	.id_csr_w_ena_o 		( id_csr_w_ena_o 		),
	.id_csr_addr_o  		( id_csr_addr_o  		),
	.id_reg_valid_o 		( id_reg_valid_o 		)
);



exe u_exe(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	.pc_i        			( id_pc_o        		),
	.op1_i       			( id_op1_o       		),
	.op2_i       			( id_op2_o       		),
	.imm_i       			( id_imm_o       		),
	.aluop_i     			( id_aluop_o     		),
	.skip_id_i   			( id_skip_o   		    ),
	.id_reg_valid_i			( id_reg_valid_o        ),
	.rd_w_ena_i  			( id_rd_w_ena_o  		),
	.rd_w_addr_i 			( id_rd_w_addr_o 		),
	.csr_data_i  			( csr_rd_data  		    ),
	.rd_w_ena_o  			( exe_rd_w_ena_i  		),
	.rd_w_addr_o 			( exe_rd_w_addr_i 		),
	.rd_data_o   			( exe_rd_w_data_i   	),
	.csr_data_o  			( csr_data_o  			),
	.aluop_o     			( exe_aluop_i     		),
	.mem_addr_o  			( exe_mem_addr_i  		),
	.rs2_o       			( exe_rs2_i       		),
	.halt_ena_o  			( exe_halt_ena_i  		),
	.skip_exe_o  			( exe_skip_i  			),
	.exe_data_valid_o		( exe_data_valid_o      )
);



exe_reg u_exe_reg(
	//ports
	.clk             		( clock             	),
	.rst             		( reset | exe_rst_i     ),
	.exe_stall_i     		( exe_stall_i     		),
    .exe_pc_i               ( id_pc_o   			),
	.exe_inst_i             ( id_inst_o				),
	.exe_rd_w_ena_i  		( exe_rd_w_ena_i  		),
	.exe_rd_w_addr_i 		( exe_rd_w_addr_i 		),
	.exe_rd_w_data_i   		( exe_rd_w_data_i   	),
	.exe_aluop_i     		( exe_aluop_i     		),
	.exe_mem_addr_i  		( exe_mem_addr_i  		),
	.exe_rs2_i       		( exe_rs2_i       		),
	.exe_halt_ena_i  		( exe_halt_ena_i  		),
	.exe_skip_i      		( exe_skip_i      		),
    .exe_pc_o               ( exe_pc_o				),
	.exe_inst_o             ( exe_inst_o			),
	.exe_reg_valid_i 		( id_reg_valid_o 		),
	.exe_rd_w_ena_o  		( exe_rd_w_ena_o  		),
	.exe_rd_w_addr_o 		( exe_rd_w_addr_o 		),
	.exe_rd_w_data_o   		( exe_rd_w_data_o   	),
	.exe_aluop_o     		( exe_aluop_o     		),
	.exe_mem_addr_o  		( exe_mem_addr_o  		),
	.exe_rs2_o       		( exe_rs2_o       		),
	.exe_halt_ena_o  		( exe_halt_ena_o  		),
	.exe_skip_o      		( exe_skip_o      		),
	.exe_reg_valid_o 		( exe_reg_valid_o 		)
);


mem #(
	.MEM_IDLE  		( 1'b0 		),
	.MEM_VALID 		( 1'b1 		))
u_mem(
	//ports
	.rst              		( reset              	),
	.rd_w_ena_i       		( exe_rd_w_ena_o       	),
	.rd_w_addr_i      		( exe_rd_w_addr_o      	),
	.rd_w_data_i      		( exe_rd_w_data_o      	),
	.aluop_i          		( exe_aluop_o          	),
	.mem_addr_i       		( exe_mem_addr_o       	),
	.rs2_i            		( exe_rs2_o            	),
	.halt_ena_i       		( exe_halt_ena_o       	),
	.skip_exe_i        		( exe_skip_o        	),
	.mtime_i				( mtime_o				),
	.mtimecmp_i				( mtimecmp_o			),
	.clint_rd_o				( clint_rd_o			),
	.clint_wr_o				( clint_wr_o			),
	.mtime_ena_o			( mtime_ena_o			),
	.mtimecmp_ena_o			( mtimecmp_ena_o		),
	.mem_read_req_o   		( mem_read_req_o   		),
	.mem_write_req_o  		( mem_write_req_o  		),
	.mem_valid_o      		( mem_valid_o      		),
	.mem_ready_i      		( mem_ready_o      		),
	.mem_addr_o       		( mem_addr_o       		),
	.mem_size_o       		( mem_size_o       		),
	.mem_data_read_i  		( mem_data_read_o  		),
	.mem_data_write_o 		( mem_data_write_o 		),
	.rd_w_ena_o       		( mem_rd_w_ena_i       	),
	.rd_w_addr_o      		( mem_rd_w_addr_i      	),
	.rd_w_data_o      		( mem_rd_w_data_i      	),
	.halt_ena_o       		( mem_halt_ena_i       	),
	.skip_mem_o       		( mem_skip_i       		),
	.mem_data_valid_o		( mem_data_valid_o      )
);


mem_reg u_mem_reg(
	//ports
	.clk             		( clock             	),
	.rst             		( reset | mem_rst_i   	),
    .mem_pc_i               ( exe_pc_o              ),
	.mem_inst_i             ( exe_inst_o            ),
	.mem_stall_i     		( mem_stall_i     		),
	.mem_rd_w_ena_i  		( mem_rd_w_ena_i  		),
	.mem_rd_w_addr_i 		( mem_rd_w_addr_i 		),
	.mem_rd_w_data_i 		( mem_rd_w_data_i 		),
	.mem_halt_ena_i  		( mem_halt_ena_i  		),
	.mem_skip_i      		( mem_skip_i      		),
	.mem_reg_valid_i 		( exe_reg_valid_o 		),
	.mem_mstatus_i   		( mstatus_o   			),
	.mem_mie_i       		( mie_o       			),
	.mem_mtvec_i			( mtvec_o				),
	.mem_mepc_i      		( mepc_o      			),
	.mem_mcause_i    		( mcause_o    			),
	.mem_mtval_i     		( mtval_o     			),
	.mem_mip_i       		( mip_o       			),
	.mem_medeleg_i 			( medeleg_o				),
	.mem_mideleg_i 			( mideleg_o				),
	.mem_mscratch_i			( mscratch_o			),	
	.mem_pc_o               ( mem_pc_o              ),
	.mem_inst_o             ( mem_inst_o			),
	.mem_rd_w_ena_o  		( mem_rd_w_ena_o  		),
	.mem_rd_w_addr_o 		( mem_rd_w_addr_o 		),
	.mem_rd_w_data_o 		( mem_rd_w_data_o 		),
	.mem_halt_ena_o  		( mem_halt_ena_o  		),
	.mem_skip_o      		( mem_skip_o      		),
	.mem_reg_valid_o 		( mem_reg_valid_o 		),
	.mem_mstatus_o   		( mem_mstatus_o   		),
	.mem_mie_o       		( mem_mie_o       		),
	.mem_mtvec_o			( mem_mtvec_o			),
	.mem_mepc_o      		( mem_mepc_o      		),
	.mem_mcause_o    		( mem_mcause_o    		),
	.mem_mtval_o     		( mem_mtval_o     		),
	.mem_mip_o       		( mem_mip_o       		),
	.mem_medeleg_o 			( mem_medeleg_o 		),
	.mem_mideleg_o 			( mem_mideleg_o 		),
	.mem_mscratch_o			( mem_mscratch_o		)

);


wb u_wb(
	//ports
	.rd_w_ena_i    			( mem_rd_w_ena_o    	),
	.rd_w_addr_i   			( mem_rd_w_addr_o   	),
	.rd_w_data_i   			( mem_rd_w_data_o   	),
	.wb_halt_ena_i 			( mem_halt_ena_o 		),
	.wb_skip_i     			( mem_skip_o     		),
	.rd_w_ena_o    			( wb_rd_w_ena_i    		),
	.rd_w_addr_o   			( wb_rd_w_addr_i   		),
	.rd_w_data_o   			( wb_rd_w_data_i   		),
	.wb_halt_ena_o 			( wb_halt_ena_i 		),
	.wb_skip_o     			( wb_skip_i     		)
);


wb_reg u_wb_reg(
	//ports
	.clk            		( clock            		),
	.rst            		( reset | wb_rst_i      ),
	.wb_stall_i     		( wb_stall_i    		), //暂时不需要暂停该级流水线
	.wb_pc_i        		( mem_pc_o        		),
	.wb_inst_i              ( mem_inst_o  			),
	.wb_rd_w_ena_i  		( wb_rd_w_ena_i  		),
	.wb_rd_w_addr_i 		( wb_rd_w_addr_i 		),
	.wb_rd_w_data_i    		( wb_rd_w_data_i    	),
	.wb_halt_ena_i  		( wb_halt_ena_i  		),
	.wb_skip_i      		( wb_skip_i      		),
	.wb_reg_valid_i 		( mem_reg_valid_o 		),
	.wb_mstatus_i   		( mem_mstatus_o       	),
	.wb_mie_i       		( mem_mie_o           	),
	.wb_mtvec_i       		( mem_mtvec_o           ),
	.wb_mepc_i      		( mem_mepc_o          	),
	.wb_mcause_i    		( mem_mcause_o        	),
	.wb_mtval_i     		( mem_mtval_o         	),
	.wb_mip_i       		( mem_mip_o           	),
	.wb_medeleg_i 			( mem_medeleg_o			),
	.wb_mideleg_i 			( mem_mideleg_o			),
	.wb_mscratch_i			( mem_mscratch_o		),
	.wb_pc_o        		( wb_pc_o        		),
	.wb_inst_o              ( wb_inst_o				),
	.wb_rd_w_ena_o  		( wb_rd_w_ena_o  		),
	.wb_rd_w_addr_o 		( wb_rd_w_addr_o 		),
	.wb_rd_w_data_o    		( wb_rd_w_data_o    	),
	.wb_halt_ena_o  		( wb_halt_ena_o  		),
	.wb_skip_o      		( wb_skip_o      		),
	.wb_reg_valid_o 		( wb_reg_valid_o 		),
	.wb_mstatus_o   		( wb_mstatus_o   		),
	.wb_mie_o       		( wb_mie_o       		),
	.wb_mtvec_o       		( wb_mtvec_o       		),
	.wb_mepc_o      		( wb_mepc_o      		),
	.wb_mcause_o    		( wb_mcause_o    		),
	.wb_mtval_o     		( wb_mtval_o     		),
	.wb_mip_o       		( wb_mip_o       		),
	.wb_medeleg_o 			( wb_medeleg_o 			),
	.wb_mideleg_o 			( wb_mideleg_o 			),
	.wb_mscratch_o			( wb_mscratch_o			)

);


regfile u_regfile(
	//ports
	.clk     				( clock     			),
	.rst     				( reset     			),
	.w_addr  				( mem_rd_w_addr_o  		),
	.w_data  				( mem_rd_w_data_o  		),
	.w_ena   				( mem_rd_w_ena_o   		),
	.r_addr1 				( id_rs1_r_addr_o 		),
	.r_data1 				( rs1_data_o 			),
	.r_ena1  				( id_rs1_r_ena_o  		),
	.r_addr2 				( id_rs2_r_addr_o 		),
	.r_data2 				( rs2_data_o 			),
	.r_ena2  				( id_rs2_r_ena_o  		),
	.regs    				( regs_o    			)
);


csr_regfile u_csr_regfile(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	.ecall_i				( id_ecall_o			),
	.mret_i					( id_mret_o				),
	.pc_i					( id_pc_o				),
	.if_reg_valid_i			( if_reg_valid_o		),
	.if_pc_i				( if_pc_o				),
	.clint_interrupt_i		( clint_interrupt_o		),
	.csr_rd_addr    		( id_csr_addr_o    		),
	.csr_wr_addr    		( id_csr_addr_o    		),
	.csr_rd_ena  			( id_csr_r_ena_o		),
	.csr_wr_ena  			( id_csr_w_ena_o		),
	.csr_wr_data 			( csr_data_o	 		),
	.clint_o				( clint_o				),
	.csr_rd_data 			( csr_rd_data 			),
	.mstatus_o   			( mstatus_o   			),
	.mie_o       			( mie_o       			),
	.mtvec_o				( mtvec_o				),
	.mepc_o      			( mepc_o      			),
	.mcause_o    			( mcause_o    			),
	.mtval_o     			( mtval_o     			),
	.mip_o       			( mip_o       			),
	.medeleg_o				( medeleg_o				),
	.mideleg_o				( mideleg_o				),
	.mscratch_o				( mscratch_o			),
	.sstatus_o				( sstatus_o				)
);

clint u_clint(
	//ports
	.clk         			( clock         		),
	.rst         			( reset         		),
	.clint_rd_i       		( clint_rd_o       		),
	.clint_wr_i       		( clint_wr_o       		),
	.mtime_ena_i      		( mtime_ena_o      		),
	.mtimecmp_ena_i   		( mtimecmp_ena_o   		),
	.mem_data_write_i 		( mem_data_write_o 		),
	.mem_size_i       		( mem_size_o       		),
	.mtime_o          		( mtime_o          		),
	.mtimecmp_o       		( mtimecmp_o       		),
	.clint_interrupt_o		( clint_interrupt_o		)
);

arbiter #(
	.ARBITER_IF  		( 1'b0 		),
	.ARBITER_MEM 		( 1'b1 		))
u_arbiter(
	//ports
	.clock            		( clock            		),
	.reset            		( reset            		),
	.if_read_req_i    		( `REQ_READ     		),
	.if_valid_i       		( if_valid_o       		),
	.if_ready_o       		( if_ready_o       		),
	.if_data_read_o   		( if_data_read_o   		),
	.if_addr_i        		( if_addr_o        		),
	.if_size          		( if_size_o          	),
	.mem_read_req_i   		( mem_read_req_o   		),
	.mem_write_req_i  		( mem_write_req_o  		),
	.mem_valid_i      		( mem_valid_o      		),
	.mem_ready_o      		( mem_ready_o      		),
	.mem_addr_i       		( mem_addr_o       		),
	.mem_size_i       		( mem_size_o       		),
	.mem_data_read_o  		( mem_data_read_o  		),
	.mem_data_write_i 		( mem_data_write_o 		),
	.rw_valid_o       		( axi_valid       		),
	.rw_ready_i       		( axi_ready       		),
	.rw_req_o         		( axi_req         		),
	.data_read_i      		( axi_data_read         ),
	.data_write_o     		( axi_data_write     	),
	.rw_addr_o        		( axi_addr        		),
	.rw_size_o        		( axi_size        		),
	.arbiter_state_o		( arbiter_state_o		)
);


data_ctr u_data_ctr(
	//ports
	.id_rs1_r_ena_i 		( id_rs1_r_ena_o 		),
	.id_rs2_r_ena_i 		( id_rs2_r_ena_o 		),
	.id_rs1_addr_i  		( id_rs1_r_addr_o  		),
	.id_rs2_addr_i  		( id_rs2_r_addr_o  		),
	.rs1_data_i     		( rs1_data_o     		),
	.rs2_data_i     		( rs2_data_o     		),
	.exe_w_ena_i    		( exe_rd_w_ena_i    	),
	.mem_w_ena_i    		( mem_rd_w_ena_i    	),
	.wb_w_ena_i     		( wb_rd_w_ena_i     	),
	.exe_w_addr_i   		( exe_rd_w_addr_i   	),
	.mem_w_addr_i   		( mem_rd_w_addr_i   	),
	.wb_w_addr_i    		( wb_rd_w_addr_i    	),
	.exe_data_valid_i		( exe_data_valid_o      ),
	.mem_data_valid_i		( mem_data_valid_o		),
	.exe_w_data_i   		( exe_rd_w_data_i   	),
	.mem_w_data_i   		( mem_rd_w_data_i   	),
	.wb_w_data_i    		( wb_rd_w_data_i    	),

	.id_rs1_data_o  		( id_rs1_data_o  		),
	.id_rs2_data_o  		( id_rs2_data_o  		),
	.id_hit_o 		        ( id_hit_o       		)
);


scu u_scu(
	//ports
	.if_ready_i  			( if_ready_o  			),
	.mem_ready_i 			( mem_ready_o 			),
	.mem_valid_i            ( mem_valid_o           ),
	.id_branch_tag_i		( id_branch_tag_o       ),
	.id_hit_i				( id_hit_o 				),
	.stall_ena_o 			( stall_ena_o 			),
	.pipe_rst_o  			( pipe_rst_o  			),
	.mem_req_o              ( mem_req_o 			)
);

//Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [`REG_WIDTH] cmt_wdata;
reg [`REG_WIDTH] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`REG_WIDTH] regs_diff [0 : 31];
reg cmt_skip;
reg cmt_clint;
reg [31:0] cmt_exception_inst;

wire [31:0] cmt_intrNO;
wire [63:0] cmt_exceptionPC;
wire [31:0] cmt_exceptionInst;

assign cmt_intrNO        = cmt_clint ? 32'd7 : 0;
assign cmt_exceptionPC   = cmt_clint ? mepc_o: 0;
assign cmt_exceptionInst = cmt_clint ? cmt_exception_inst:0;

always @(posedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt,cmt_clint,cmt_exception_inst} <= 0;
  end
  else if (~trap) begin
	cmt_wen   <= wb_rd_w_ena_o;
	cmt_wdest <= wb_rd_w_addr_o;    
	cmt_wdata <= wb_rd_w_data_o;    
	cmt_pc    <= wb_pc_o;
	cmt_inst  <= wb_inst_o;
	cmt_valid <= wb_reg_valid_o;
	cmt_skip  <= wb_skip_o;   
	cmt_clint <= clint_o;
	cmt_exception_inst <= if_inst_o;   


    trap <= wb_inst_o[6:0] == 7'h6b;
    trap_code <= regs_o[10][7:0];
    cycleCnt <= cycleCnt + 1;
    instrCnt <= instrCnt + wb_reg_valid_o;
  end
end

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .special            (0),
  .skip               (cmt_skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_o[0]),
  .gpr_1              (regs_o[1]),
  .gpr_2              (regs_o[2]),
  .gpr_3              (regs_o[3]),
  .gpr_4              (regs_o[4]),
  .gpr_5              (regs_o[5]),
  .gpr_6              (regs_o[6]),
  .gpr_7              (regs_o[7]),
  .gpr_8              (regs_o[8]),
  .gpr_9              (regs_o[9]),
  .gpr_10             (regs_o[10]),
  .gpr_11             (regs_o[11]),
  .gpr_12             (regs_o[12]),
  .gpr_13             (regs_o[13]),
  .gpr_14             (regs_o[14]),
  .gpr_15             (regs_o[15]),
  .gpr_16             (regs_o[16]),
  .gpr_17             (regs_o[17]),
  .gpr_18             (regs_o[18]),
  .gpr_19             (regs_o[19]),
  .gpr_20             (regs_o[20]),
  .gpr_21             (regs_o[21]),
  .gpr_22             (regs_o[22]),
  .gpr_23             (regs_o[23]),
  .gpr_24             (regs_o[24]),
  .gpr_25             (regs_o[25]),
  .gpr_26             (regs_o[26]),
  .gpr_27             (regs_o[27]),
  .gpr_28             (regs_o[28]),
  .gpr_29             (regs_o[29]),
  .gpr_30             (regs_o[30]),
  .gpr_31             (regs_o[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);


DifftestArchEvent DifftestArchEvent(
	//ports
	.clock         		( clock         		),
	.coreid        		( 0		        		),
	.intrNO        		( cmt_intrNO		    ),
	.cause         		( 0			         	),
	.exceptionPC   		( cmt_exceptionPC  		),
	.exceptionInst 		( cmt_exceptionInst		)
);

wire [`REG_WIDTH] 	cmt_mstatus_o ;
wire [`REG_WIDTH] 	cmt_mepc_o    ;
wire [`REG_WIDTH] 	cmt_mtval_o   ;
wire [`REG_WIDTH] 	cmt_mtvec_o   ;
wire [`REG_WIDTH] 	cmt_mcause_o  ;
wire [`REG_WIDTH] 	cmt_mip_o     ;
wire [`REG_WIDTH] 	cmt_mie_o     ;

assign cmt_mstatus_o = cmt_clint ? mstatus_o: wb_mstatus_o ;
assign cmt_mepc_o    = cmt_clint ? mepc_o   : wb_mepc_o    ;
assign cmt_mtval_o   = cmt_clint ? mtval_o  : wb_mtval_o   ;
assign cmt_mtvec_o   = cmt_clint ? mtvec_o  : wb_mtvec_o   ;
assign cmt_mcause_o  = cmt_clint ? mcause_o : wb_mcause_o  ;
assign cmt_mip_o     = cmt_clint ? mip_o    : wb_mip_o     ;
assign cmt_mie_o     = cmt_clint ? mie_o    : wb_mie_o     ;
 
DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (`RISCV_PRIV_MODE_M),
  .mstatus            (mstatus_o),
  .sstatus            (sstatus_o),
  .mepc               (mepc_o),
  .sepc               (0),
  .mtval              (mtval_o),
  .stval              (0),
  .mtvec              (mtvec_o),
  .stvec              (0),
  .mcause             (mcause_o),
  .scause             (0),
  .satp               (0),
  .mip                (mip_o),
  .mie                (mie_o),
  .mscratch           (mscratch_o),
  .sscratch           (0),
  .mideleg            (mideleg_o),
  .medeleg            (medeleg_o)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);






endmodule